import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import * as React from 'react';
import hash from '@emotion/hash';
import { ATTR_TOKEN, CSS_IN_JS_INSTANCE, CSS_IN_JS_INSTANCE_ID } from "../StyleContext";
import useGlobalCache from "./useGlobalCache";
import { flattenToken, token2key } from "../util";
var EMPTY_OVERRIDE = {}; // Generate different prefix to make user selector break in production env.
// This helps developer not to do style override directly on the hash id.

var hashPrefix = process.env.NODE_ENV !== 'production' ? 'css-dev-only-do-not-override' : 'css';
var tokenKeys = new Map();

function recordCleanToken(tokenKey) {
  tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) + 1);
}

function removeStyleTags(key) {
  if (typeof document !== 'undefined') {
    var styles = document.querySelectorAll("style[".concat(ATTR_TOKEN, "=\"").concat(key, "\"]"));
    styles.forEach(function (style) {
      if (style[CSS_IN_JS_INSTANCE] === CSS_IN_JS_INSTANCE_ID) {
        var _style$parentNode;

        (_style$parentNode = style.parentNode) === null || _style$parentNode === void 0 ? void 0 : _style$parentNode.removeChild(style);
      }
    });
  }
} // Remove will check current keys first


function cleanTokenStyle(tokenKey) {
  tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) - 1);
  var tokenKeyList = Array.from(tokenKeys.keys());
  var cleanableKeyList = tokenKeyList.filter(function (key) {
    var count = tokenKeys.get(key) || 0;
    return count <= 0;
  });

  if (cleanableKeyList.length < tokenKeyList.length) {
    cleanableKeyList.forEach(function (key) {
      removeStyleTags(key);
      tokenKeys.delete(key);
    });
  }
}
/**
 * Cache theme derivative token as global shared one
 * @param theme Theme entity
 * @param tokens List of tokens, used for cache. Please do not dynamic generate object directly
 * @param option Additional config
 * @returns Call Theme.getDerivativeToken(tokenObject) to get token
 */


export default function useCacheToken(theme, tokens) {
  var option = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  var _option$salt = option.salt,
      salt = _option$salt === void 0 ? '' : _option$salt,
      _option$override = option.override,
      override = _option$override === void 0 ? EMPTY_OVERRIDE : _option$override,
      formatToken = option.formatToken; // Basic - We do basic cache here

  var mergedToken = React.useMemo(function () {
    return Object.assign.apply(Object, [{}].concat(_toConsumableArray(tokens)));
  }, [tokens]);
  var tokenStr = React.useMemo(function () {
    return flattenToken(mergedToken);
  }, [mergedToken]);
  var overrideTokenStr = React.useMemo(function () {
    return flattenToken(override);
  }, [override]);
  var cachedToken = useGlobalCache('token', [salt, theme.id, tokenStr, overrideTokenStr], function () {
    var derivativeToken = theme.getDerivativeToken(mergedToken); // Merge with override

    var mergedDerivativeToken = _objectSpread(_objectSpread({}, derivativeToken), override); // Format if needed


    if (formatToken) {
      mergedDerivativeToken = formatToken(mergedDerivativeToken);
    } // Optimize for `useStyleRegister` performance


    var tokenKey = token2key(mergedDerivativeToken, salt);
    mergedDerivativeToken._tokenKey = tokenKey;
    recordCleanToken(tokenKey);
    var hashId = "".concat(hashPrefix, "-").concat(hash(tokenKey));
    mergedDerivativeToken._hashId = hashId; // Not used

    return [mergedDerivativeToken, hashId];
  }, function (cache) {
    // Remove token will remove all related style
    cleanTokenStyle(cache[0]._tokenKey);
  });
  return cachedToken;
}